/*
 * CombinatorialParsers.scala
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.marverse.language

import scala.collection.mutable.{ArrayBuffer}

class SeqParser[-T, +R](val seq: Seq[Parser[T, R]])
extends Parser[T, Seq[R]] {

  override def parse[S <: T](in: Stream[S]): ParseResult[S, Seq[R]] = {
	var cur = in
	val result = new ArrayBuffer[R]()
	for(p <- seq)
      p.parse(cur) match {
        case Success(remaining, r) => { cur = remaining; result.append(r) }
        case SuccessOmit(remaining) => { cur = remaining }
        case Failure => return Failure
        case f: FailureAccept[S] => return f
      }
	Success(cur, result)
  }

  def ~[S <: T, Q >: R](next: Parser[S, Q]): SeqParser[S, Q] =
    new SeqParser[S, Q](seq ++ Seq(next))
  override def leftMost = seq.first.leftMost
  override def rightMost = seq.last.rightMost
  override def toString = seq.mkString("", "~", "")
}

class RepParser[-T, +R](val inner: Parser[T, R],
                        val delim: Parser[T, R],
                        val min: Int,
                        val max: Int)
extends Parser[T, Seq[R]] {

  override def parse[S <: T](in: Stream[S]): ParseResult[S, Seq[R]] = {
    val result = new ArrayBuffer[R]()
    var cur = in
    var num = 0

    def parseInner(from: Stream[S]): Option[ParseResult[S, Seq[R]]] =
    inner.parse(from) match {
      case Success(remaining, r) => {
        result.append(r)
        cur = remaining
        num += 1
        None
      }
      case SuccessOmit(remaining) => { 
        cur = remaining
        num += 1
        None
      }
      case Failure => {
        if (min <= num) Some(Success(cur, result.readOnly))
        else Some(Failure)
      }
      case f: FailureAccept[S] =>
        Some(f)
    }

    parseInner(cur) match { case Some(r) => return r; case None => }

    while(max == 0 || num < max)
    delim.parse(cur) match {
      case Success(remaining, r) => {
        result.append(r)
        parseInner(remaining) match { case Some(r) => return r; case None => }
      }
      case SuccessOmit(remaining) =>
        parseInner(remaining) match { case Some(r) => return r; case None => }
      case f: FailureAccept[S] => return f
      case Failure => if (min <= num) return Success(cur, result.readOnly)
                      else return Failure
    }

    Success(cur, result.readOnly)
  }

  override def leftMost: Parser[_ >: T, _] = inner.leftMost
  override def rightMost: Parser[_ >: T, _] = inner.rightMost
  override def toString = {
    val f = if (min == 0 && max == 1) "[%s]?"
    else if (max == 0 && min == 0) "[%s]*[%s]"
    else if (max == 0) "[%s]*[%s, %d]"
    else "[%s]*[%s, %d, %d]"
    f.format(inner.toString, delim.toString, min, max)
  }

}

class TransformParser[-T, A, +B](val inner: Parser[_ >: T, A],
                                  val transform: A => B)
extends Parser[T, B] {
  override def parse[S <: T](in: Stream[S]): ParseResult[S, B] =
    inner.parse(in) match {
      case Success(remaining, r) => Success(remaining, transform(r))
      case r: SuccessOmit[S] => r
      case Failure => Failure
      case r: FailureAccept[S] => r
    }

  override def leftMost: Parser[_ >: T, _] = inner.leftMost
  override def rightMost: Parser[_ >: T, _] = inner.rightMost
  override def toString = inner.toString
}

class ConstParser[-T, +R](val inner: Parser[T, _], val value: R)
extends Parser[T, R] {
  override def parse[S <: T](in: Stream[S]): ParseResult[S, R] =
    inner.parse(in) match {
      case Success(remaining, r) => Success(remaining, value)
      case SuccessOmit(remaining) => Success(remaining, value)
      case Failure => Failure
      case r: FailureAccept[S] => r
    }

  override def leftMost: Parser[_ >: T, _] = inner.leftMost
  override def rightMost: Parser[_ >: T, _] = inner.rightMost
  override def toString = "%s := %s".format(inner.toString, value.toString)
}

